package org.kinglone.utlis.dao;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.jdbc.Work;
import org.kinglone.utlis.GenericsUtils;
import org.kinglone.utlis.PageQuery;
import org.kinglone.utlis.PageResults;
import org.kinglone.utlis.PageResultsObject;
import org.kinglone.utlis.RowMapper;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {

	protected Class<T> entityClass;
	
	@Resource(name = "hibernateTemplate")
	public void setSupperHibernateTemplate(HibernateTemplate hibernateTemplate){
		setHibernateTemplate(hibernateTemplate);
	}
	
	@Resource(name = "sessionFactory")
	public void setSupperSessionFactory(SessionFactory sessionFactory){
		setSessionFactory(sessionFactory);
	}

	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		entityClass = GenericsUtils.getSuperClassGenricType(getClass());
	}

	protected Class getEntityClass() {
		if (entityClass == null) {
			entityClass = GenericsUtils.getSuperClassGenricType(getClass());
		}
		return entityClass;
	}

	/**
	 * <保存实体> <完整保存实体>
	 * 
	 * @param t
	 *            实体参数
	 * @see com.itv.launcher.util.IBaseDao#save(java.lang.Object)
	 */
	@Transactional
	public void save(T t) {
		this.getSession().save(t);
	}
	
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void save(String entityName, Object entity) {
		getHibernateTemplate().save(entityName, entity);
	}

	/**
	 * <保存或者更新实体>
	 * 
	 * @param t
	 *            实体
	 * @see com.itv.launcher.util.IBaseDao#saveOrUpdate(java.lang.Object)
	 */
	@Transactional
	public void saveOrUpdate(T t) {
		this.getSession().saveOrUpdate(t);
		this.getSession().flush();
	}

	/**
	 * <load> <加载实体的load方法>
	 * 
	 * @param id
	 *            实体的id
	 * @return 查询出来的实体
	 * @see com.itv.launcher.util.IBaseDao#load(java.io.Serializable)
	 */
	 @Transactional
	public T load(Serializable id) {
		T load = (T) this.getSession().load(getEntityClass(), id);
		return load;
	}

	/**
	 * <get> <查找的get方法>
	 * 
	 * @param id
	 *            实体的id
	 * @return 查询出来的实体
	 * @see com.itv.launcher.util.IBaseDao#get(java.io.Serializable)
	 */
	 @Transactional
	public T get(Serializable id) {
		T load = (T) this.getSession().get(getEntityClass(), id);
		return load;
	}

	/**
	 * <contains>
	 * 
	 * @param t
	 *            实体
	 * @return 是否包含
	 * @see com.itv.launcher.util.IBaseDao#contains(java.lang.Object)
	 */
	
	public boolean contains(T t) {
		return this.getSession().contains(t);
	}

	/**
	 * <delete> <删除表中的t数据>
	 * 
	 * @param t
	 *            实体
	 * @see com.itv.launcher.util.IBaseDao#delete(java.lang.Object)
	 */
	@Transactional
	public void delete(T t) {
		this.getSession().delete(t);
	}

	/**
	 * <根据ID删除数据>
	 * 
	 * @param Id
	 *            实体id
	 * @return 是否删除成功
	 * @see com.itv.launcher.util.IBaseDao#deleteById(java.io.Serializable)
	 */
	@Transactional
	public boolean deleteById(Serializable Id) {
		T t = get(Id);
		if (t == null) {
			return false;
		}
		delete(t);
		return true;
	}

	/**
	 * <删除所有>
	 * 
	 * @param entities
	 *            实体的Collection集合
	 * @see com.itv.launcher.util.IBaseDao#deleteAll(java.util.Collection)
	 */
	@Transactional
	public void deleteAll(Collection<T> entities) {
		for (Object entity : entities) {
			this.getSession().delete(entity);
		}
	}

	/**
	 * <执行Hql语句>
	 * 
	 * @param hqlString
	 *            hql
	 * @param values
	 *            不定参数数组
	 * @see com.itv.launcher.util.IBaseDao#queryHql(java.lang.String,
	 *      java.lang.Object[])
	 */
	 @Transactional
	public void queryHql(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		query.executeUpdate();
	}

	/**
	 * <执行Sql语句>
	 * 
	 * @param sqlString
	 *            sql
	 * @param values
	 *            不定参数数组
	 * @see com.itv.launcher.util.IBaseDao#querySql(java.lang.String,
	 *      java.lang.Object[])
	 */
	 @Transactional
	public void querySql(String sqlString, Object... values) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		query.executeUpdate();
	}

	/**
	 * <根据HQL语句查找唯一实体>
	 * 
	 * @param hqlString
	 *            HQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 查询实体
	 * @see com.itv.launcher.util.IBaseDao#getByHQL(java.lang.String,
	 *      java.lang.Object[])
	 */
	 @Transactional
	public T getByHQL(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		query.setMaxResults(1);
		return (T) query.uniqueResult();
	}

	/**
	 * <根据SQL语句查找唯一实体>
	 * 
	 * @param sqlString
	 *            SQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 查询实体
	 * @see com.itv.launcher.util.IBaseDao#getBySQL(java.lang.String,
	 *      java.lang.Object[])
	 */
	 @Transactional
	public T getBySQL(String sqlString, Object... values) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		query.setMaxResults(1);
		return (T) query.uniqueResult();
	}

	/**
	 * <根据HQL语句，得到对应的list>
	 * 
	 * @param hqlString
	 *            HQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 查询多个实体的List集合
	 * @see com.itv.launcher.util.IBaseDao#getListByHQL(java.lang.String,
	 *      java.lang.Object[])
	 */
	 @Transactional
	public List<T> getListByHQL(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.list();
	}

	/**
	 * <根据SQL语句，得到对应的list>
	 * 
	 * @param sqlString
	 *            HQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 查询多个实体的List集合
	 * @see com.itv.launcher.util.IBaseDao#getListBySQL(java.lang.String,
	 *      java.lang.Object[])
	 */
	 @Transactional
	public List<T> getListBySQL(String sqlString, Object... values) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.list();
	}

	/**
	 * 由sql语句得到List
	 * 
	 * @param sql
	 * @param map
	 * @param values
	 * @return List
	 * @see com.itv.launcher.util.IBaseDao#findListBySql(java.lang.String,
	 *      com.itv.launcher.util.RowMapper, java.lang.Object[])
	 */
	 @Transactional
	public List findListBySql(final String sql, final RowMapper map, final Object... values) {
		final List list = new ArrayList();
		// 执行JDBC的数据批量保存
		Work jdbcWork = new Work() {
			public void execute(Connection connection) throws SQLException {

				PreparedStatement ps = null;
				ResultSet rs = null;
				try {
					ps = connection.prepareStatement(sql);
					for (int i = 0; i < values.length; i++) {
						setParameter(ps, i, values[i]);

					}

					rs = ps.executeQuery();
					int index = 0;
					while (rs.next()) {
						Object obj = map.mapRow(rs, index++);
						list.add(obj);

					}
				} finally {
					if (rs != null) {
						rs.close();

					}
					if (ps != null) {
						ps.close();
					}
				}
			}
		};
		this.getSession().doWork(jdbcWork);
		return list;
	}

	/**
	 * <refresh>
	 * 
	 * @param t
	 *            实体
	 * @see com.itv.launcher.util.IBaseDao#refresh(java.lang.Object)
	 */
	 @Transactional
	public void refresh(T t) {
		this.getSession().refresh(t);
	}

	/**
	 * <update>
	 * 
	 * @param t
	 *            实体
	 * @see com.itv.launcher.util.IBaseDao#update(java.lang.Object)
	 */
	 @Transactional
	public void update(T t) {
		this.getSession().update(t);
	}


	/**
	 * <根据HQL得到记录数>
	 * 
	 * @param hql
	 *            HQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 记录总数
	 * @see com.itv.launcher.util.IBaseDao#countByHql(java.lang.String,
	 *      java.lang.Object[])
	 */
	 @Transactional
	public Long countByHql(String hql, Map<String, Object> values) {
		Query query = this.getSession().createQuery(hql);
		if (values != null) {
			for(String key : values.keySet()){
				query.setParameter(key, values.get(key));
			}
		}
		return (Long) query.uniqueResult();
	}

	/**
	 * <根据HQL得到记录数>
	 * 
	 * @param sql
	 *            SQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 记录总数
	 * @see
	 */
	 @Transactional
	public int countBySql(String sql, Map<String, Object> values) {
		Query query = this.getSession().createSQLQuery(sql);
		if (values != null) {
			for(String key : values.keySet()){
				query.setParameter(key, values.get(key));
			}
		}
		return Integer.parseInt((query.uniqueResult()==null)?"0.0":query.uniqueResult().toString());
	}


	/**
	 * 
	 * @return session
	 */
	
	public Session getSession() {
		// 需要开启事物，才能得到CurrentSession
		return getHibernateTemplate().getSessionFactory().getCurrentSession();
	}

	/**
	 * 
	 * 设置每行批处理参数
	 * 
	 * @param ps
	 * @param pos
	 *            ?占位符索引，从0开始
	 * @param data
	 * @throws SQLException
	 * @see [类、类#方法、类#成员]
	 */
	private void setParameter(PreparedStatement ps, int pos, Object data) throws SQLException {
		if (data == null) {
			ps.setNull(pos + 1, Types.VARCHAR);
			return;
		}
		Class dataCls = data.getClass();
		if (String.class.equals(dataCls)) {
			ps.setString(pos + 1, (String) data);
		} else if (boolean.class.equals(dataCls)) {
			ps.setBoolean(pos + 1, ((Boolean) data));
		} else if (int.class.equals(dataCls)) {
			ps.setInt(pos + 1, (Integer) data);
		} else if (double.class.equals(dataCls)) {
			ps.setDouble(pos + 1, (Double) data);
		} else if (Date.class.equals(dataCls)) {
			Date val = (Date) data;
			ps.setTimestamp(pos + 1, new Timestamp(val.getTime()));
		} else if (BigDecimal.class.equals(dataCls)) {
			ps.setBigDecimal(pos + 1, (BigDecimal) data);
		} else {
			// 未知类型
			ps.setObject(pos + 1, data);
		}

	}

	
	public List findListBySql(String sql, org.springframework.jdbc.core.RowMapper map, Object... values) {
		// TODO Auto-generated method stub
		return null;
	}
	
	/**
	 * 获取全部对象 本方法是事务安全的.
	 * 
	 * @see HibernateGenericDao#getAll(Class)
	 */
	 @Transactional
	public List<T> getAll() {
		return getAll(getEntityClass());
	}
	
	/**
	 * 获取全部对象. 本方法是事务安全的.
	 */
	 @Transactional
	public List<T> getAll(Class<T> entityClass) {
		return getHibernateTemplate().loadAll(entityClass);
	}
	 @Transactional
	@Override
	public PageResults<T> findPageByFetchedHql(String hql, String countHql, PageQuery pageQuery, Map<String, Object> values) {
		return this.findPageByFetchedHql(hql, countHql,  pageQuery.getCurrentPage(), pageQuery.getPageSize(), values);
	}

	
	
	@Override
	 @Transactional
	public PageResults<T> findPageByFetchedHql(String hql, String countHql, int pageNo, int pageSize,
			Map<String, Object> values) {
		PageResults<T> retValue = new PageResults<T>();
		Query query = this.getSession().createQuery(hql);
		if (values != null) {
			for(String key : values.keySet()){
				query.setParameter(key, values.get(key));
			}
		}
		int currentPage = pageNo > 1 ? pageNo : 1;
		retValue.setCurrentPage(currentPage);
		retValue.setPageSize(pageSize);
		if (countHql == null) {
			ScrollableResults results = query.scroll();
			results.last();
			retValue.setTotalCount(results.getRowNumber() + 1);// 设置总记录数
		} else {
			Long count = countByHql(countHql, values);
			retValue.setTotalCount(count.intValue());
		}
		retValue.resetPageNo();
		List<T> itemList = query.setFirstResult((currentPage - 1) * pageSize).setMaxResults(pageSize).list();
		if (itemList == null) {
			itemList = new ArrayList<T>();
		}
		retValue.setResults(itemList);

		return retValue;
	}
	
	@Override
	 @Transactional
	public PageResults<T> findPageByHqlAndCountSql(String hql, String countSql, PageQuery pageQuery, Map<String, Object> values,Map<String, Object> sqlvalues) {
		return this.findPageByHqlAndCountSql(hql, countSql,  pageQuery.getCurrentPage(), pageQuery.getPageSize(), values, sqlvalues);
	}

	
	
	@Override
	 @Transactional
	public PageResults<T> findPageByHqlAndCountSql(String hql, String countSql, int pageNo, int pageSize,
			Map<String, Object> values, Map<String, Object> sqlvalues) {
		PageResults<T> retValue = new PageResults<T>();
		Query query = this.getSession().createQuery(hql);
		if (values != null) {
			for(String key : values.keySet()){
				query.setParameter(key, values.get(key));
			}
		}
		int currentPage = pageNo > 1 ? pageNo : 1;
		retValue.setCurrentPage(currentPage);
		retValue.setPageSize(pageSize);
		if (countSql == null) {
			ScrollableResults results = query.scroll();
			results.last();
			retValue.setTotalCount(results.getRowNumber() + 1);// 设置总记录数
		} else {
			int count = countBySql(countSql, sqlvalues);
			retValue.setTotalCount(count);
		}
		retValue.resetPageNo();
		List<T> itemList = query.setFirstResult((currentPage - 1) * pageSize).setMaxResults(pageSize).list();
		if (itemList == null) {
			itemList = new ArrayList<T>();
		}
		retValue.setResults(itemList);

		return retValue;
	}

	@Override
	 @Transactional
	public PageResultsObject findPageByFetchedSql(String sql, String countSql, int pageNo, int pageSize,
			Map<String, Object> values) {
		PageResultsObject retValue = new PageResultsObject();
		Query query = this.getSession().createSQLQuery(sql);
		if (values != null) {
			for(String key : values.keySet()){
				query.setParameter(key, values.get(key));
			}
		}
		int currentPage = pageNo > 1 ? pageNo : 1;
		retValue.setCurrentPage(currentPage);
		retValue.setPageSize(pageSize);
		
		int count = countBySql(countSql, values);
		retValue.setTotalCount(count);
		
		retValue.resetPageNo();
		List<Object[]> itemList = query.setFirstResult((currentPage - 1) * pageSize).setMaxResults(pageSize).list();
		if (itemList == null) {
			itemList = new ArrayList<Object[]>();
		}
		retValue.setResults(itemList);
		return retValue;
	}

	@Override
	 @Transactional
	public PageResultsObject findPageByFetchedSql(String sql, String countSql, PageQuery pageQuery,
			Map<String, Object> values) {
		return this.findPageByFetchedSql(sql, countSql,  pageQuery.getCurrentPage(), pageQuery.getPageSize(), values);
	}
	
	@Override
	 @Transactional
	public int executeUpdateHql(String hql,Object... values){
		Query query  =this.getSession().createQuery(hql); 
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		int count = query.executeUpdate();
		return count;
	}
	
	@Override
	 @Transactional
	public int executeUpdateSql(String sql,Object... values){
		Query query  =this.getSession().createSQLQuery(sql); 
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		int count = query.executeUpdate();
		return count;
	}
}
